Properties

Stored Properties

                  struct FixedLengthRange {

    var firstValue: Int

    let length: Int

}

var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)

// the range represents integer values 0, 1, and 2

rangeOfThreeItems.firstValue = 6

// the range now represents integer values 6, 7, and 8
                

Stored Properties of Constant Structure Instances

                  let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)

// this range represents integer values 0, 1, 2, and 3

rangeOfFourItems.firstValue = 6

// this will report an error, even though firstValue is a variable property
                

Lazy Stored Properties

                  class DataImporter {

    /*

    DataImporter is a class to import data from an external file.

    The class is assumed to take a nontrivial amount of time to initialize.

    */

    var filename = "data.txt"

    // the DataImporter class would provide data importing functionality here

}



class DataManager {

    lazy var importer = DataImporter()

    var data = [String]()

    // the DataManager class would provide data management functionality here

}



let manager = DataManager()

manager.data.append("Some data")

manager.data.append("Some more data")

// the DataImporter instance for the importer property has not yet been created
                
                  print(manager.importer.filename)

// the DataImporter instance for the importer property has now been created

// Prints "data.txt"
                

Computed Properties

                  struct Point {

    var x = 0.0, y = 0.0

}

struct Size {

    var width = 0.0, height = 0.0

}

struct Rect {

    var origin = Point()

    var size = Size()

    var center: Point {

        get {

            let centerX = origin.x + (size.width / 2)

            let centerY = origin.y + (size.height / 2)

            return Point(x: centerX, y: centerY)

        }

        set(newCenter) {

            origin.x = newCenter.x - (size.width / 2)

            origin.y = newCenter.y - (size.height / 2)

        }

    }

}

var square = Rect(origin: Point(x: 0.0, y: 0.0),

                  size: Size(width: 10.0, height: 10.0))

let initialSquareCenter = square.center

square.center = Point(x: 15.0, y: 15.0)

print("square.origin is now at (\(square.origin.x), \(square.origin.y))")

// Prints "square.origin is now at (10.0, 10.0)"
                

Shorthand Setter Declaration

                  struct AlternativeRect {

    var origin = Point()

    var size = Size()

    var center: Point {

        get {

            let centerX = origin.x + (size.width / 2)

            let centerY = origin.y + (size.height / 2)

            return Point(x: centerX, y: centerY)

        }

        set {

            origin.x = newValue.x - (size.width / 2)

            origin.y = newValue.y - (size.height / 2)

        }

    }

}
                

Shorthand Getter Declaration

                  struct CompactRect {

    var origin = Point()

    var size = Size()

    var center: Point {

        get {

            Point(x: origin.x + (size.width / 2),

                  y: origin.y + (size.height / 2))

        }

        set {

            origin.x = newValue.x - (size.width / 2)

            origin.y = newValue.y - (size.height / 2)

        }

    }

}
                

Read-Only Computed Properties

                  struct Cuboid {

    var width = 0.0, height = 0.0, depth = 0.0

    var volume: Double {

        return width * height * depth

    }

}

let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)

print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")

// Prints "the volume of fourByFiveByTwo is 40.0"
                

Property Observers

                  class StepCounter {

    var totalSteps: Int = 0 {

        willSet(newTotalSteps) {

            print("About to set totalSteps to \(newTotalSteps)")

        }

        didSet {

            if totalSteps > oldValue  {

                print("Added \(totalSteps - oldValue) steps")

            }

        }

    }

}

let stepCounter = StepCounter()

stepCounter.totalSteps = 200

// About to set totalSteps to 200

// Added 200 steps

stepCounter.totalSteps = 360

// About to set totalSteps to 360

// Added 160 steps

stepCounter.totalSteps = 896

// About to set totalSteps to 896

// Added 536 steps
                

Property Wrappers

                  @propertyWrapper

struct TwelveOrLess {

    private var number: Int

    init() { self.number = 0 }

    var wrappedValue: Int {

        get { return number }

        set { number = min(newValue, 12) }

    }

}
                
                  struct SmallRectangle {

    @TwelveOrLess var height: Int

    @TwelveOrLess var width: Int

}



var rectangle = SmallRectangle()

print(rectangle.height)

// Prints "0"



rectangle.height = 10

print(rectangle.height)

// Prints "10"



rectangle.height = 24

print(rectangle.height)

// Prints "12"
                
                  struct SmallRectangle {

    private var _height = TwelveOrLess()

    private var _width = TwelveOrLess()

    var height: Int {

        get { return _height.wrappedValue }

        set { _height.wrappedValue = newValue }

    }

    var width: Int {

        get { return _width.wrappedValue }

        set { _width.wrappedValue = newValue }

    }

}
                

Setting Initial Values for Wrapped Properties

                  @propertyWrapper

struct SmallNumber {

    private var maximum: Int

    private var number: Int



    var wrappedValue: Int {

        get { return number }

        set { number = min(newValue, maximum) }

    }



    init() {

        maximum = 12

        number = 0

    }

    init(wrappedValue: Int) {

        maximum = 12

        number = min(wrappedValue, maximum)

    }

    init(wrappedValue: Int, maximum: Int) {

        self.maximum = maximum

        number = min(wrappedValue, maximum)

    }

}
                
                  struct ZeroRectangle {

    @SmallNumber var height: Int

    @SmallNumber var width: Int

}



var zeroRectangle = ZeroRectangle()

print(zeroRectangle.height, zeroRectangle.width)

// Prints "0 0"
                
                  struct UnitRectangle {

    @SmallNumber var height: Int = 1

    @SmallNumber var width: Int = 1

}



var unitRectangle = UnitRectangle()

print(unitRectangle.height, unitRectangle.width)

// Prints "1 1"
                
                  struct NarrowRectangle {

    @SmallNumber(wrappedValue: 2, maximum: 5) var height: Int

    @SmallNumber(wrappedValue: 3, maximum: 4) var width: Int

}



var narrowRectangle = NarrowRectangle()

print(narrowRectangle.height, narrowRectangle.width)

// Prints "2 3"



narrowRectangle.height = 100

narrowRectangle.width = 100

print(narrowRectangle.height, narrowRectangle.width)

// Prints "5 4"
                
                  struct MixedRectangle {

    @SmallNumber var height: Int = 1

    @SmallNumber(maximum: 9) var width: Int = 2

}



var mixedRectangle = MixedRectangle()

print(mixedRectangle.height)

// Prints "1"



mixedRectangle.height = 20

print(mixedRectangle.height)

// Prints "12"
                

Projecting a Value From a Property Wrapper

                  @propertyWrapper

struct SmallNumber {

    private var number: Int

    var projectedValue: Bool

    init() {

        self.number = 0

        self.projectedValue = false

    }

    var wrappedValue: Int {

        get { return number }

        set {

            if newValue > 12 {

                number = 12

                projectedValue = true

            } else {

                number = newValue

                projectedValue = false

            }

        }

    }

}

struct SomeStructure {

    @SmallNumber var someNumber: Int

}

var someStructure = SomeStructure()



someStructure.someNumber = 4

print(someStructure.$someNumber)

// Prints "false"



someStructure.someNumber = 55

print(someStructure.$someNumber)

// Prints "true"
                
                  enum Size {

    case small, large

}



struct SizedRectangle {

    @SmallNumber var height: Int

    @SmallNumber var width: Int



    mutating func resize(to size: Size) -> Bool {

        switch size {

        case .small:

            height = 10

            width = 20

        case .large:

            height = 100

            width = 100

        }

        return $height || $width

    }

}
                

Type Property Syntax

                  struct SomeStructure {

    static var storedTypeProperty = "Some value."

    static var computedTypeProperty: Int {

        return 1

    }

}

enum SomeEnumeration {

    static var storedTypeProperty = "Some value."

    static var computedTypeProperty: Int {

        return 6

    }

}

class SomeClass {

    static var storedTypeProperty = "Some value."

    static var computedTypeProperty: Int {

        return 27

    }

    class var overrideableComputedTypeProperty: Int {

        return 107

    }

}
                

Querying and Setting Type Properties

                  print(SomeStructure.storedTypeProperty)

// Prints "Some value."

SomeStructure.storedTypeProperty = "Another value."

print(SomeStructure.storedTypeProperty)

// Prints "Another value."

print(SomeEnumeration.computedTypeProperty)

// Prints "6"

print(SomeClass.computedTypeProperty)

// Prints "27"
                
                  struct AudioChannel {

    static let thresholdLevel = 10

    static var maxInputLevelForAllChannels = 0

    var currentLevel: Int = 0 {

        didSet {

            if currentLevel > AudioChannel.thresholdLevel {

                // cap the new audio level to the threshold level

                currentLevel = AudioChannel.thresholdLevel

            }

            if currentLevel > AudioChannel.maxInputLevelForAllChannels {

                // store this as the new overall maximum input level

                AudioChannel.maxInputLevelForAllChannels = currentLevel

            }

        }

    }

}
                
                  var leftChannel = AudioChannel()

var rightChannel = AudioChannel()
                
                  leftChannel.currentLevel = 7

print(leftChannel.currentLevel)

// Prints "7"

print(AudioChannel.maxInputLevelForAllChannels)

// Prints "7"
                
                  rightChannel.currentLevel = 11

print(rightChannel.currentLevel)

// Prints "10"

print(AudioChannel.maxInputLevelForAllChannels)

// Prints "10"